/*                                                     
 * $Id: class_hello.c,v 1.5 2021/03/05 23:58:21 corbet Exp $ 
 */                                                    
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Feng Liu<eric_liufeng@163.com>");
MODULE_DESCRIPTION("CLASS_HELLO_AUTO_DEV");

#define CLASSNAME "class_hello" 
#define DEVNAME "dev_hello"

static int major =   0;
static int minor =   0;
static int nr_devs = 4;

static dev_t dev;
static struct class * class_hello_class;
static struct cdev * class_hello_cdev;

 
static int class_hello_open(struct inode *inode,struct file *flp)
{
	return 0;
}
 
static int class_hello_close(struct inode *inode,struct file *flp)
{
		return 0;
}
static struct file_operations class_hello_fops={
    .owner = THIS_MODULE,
    .open = class_hello_open,
    .release = class_hello_close,
};

static int __init class_hello_init(void)
{
    int error;
    char buf[1024];
 
    memset(buf, 0x0, 1024);
    error = alloc_chrdev_region(&dev, minor, nr_devs, "class_hello");
    if (error)
    {
        printk(KERN_ERR "class hello: alloc_chardev_region failed!\n");
        goto out;
    }
    major = MAJOR(dev);
    printk(KERN_WARNING "alloc major %d\n", major);

    class_hello_cdev = cdev_alloc();
    if (class_hello_cdev == NULL)
    {
        printk(KERN_ERR "class hello: alloc cdev failed!\n");
        error = -ENOMEM;
        goto out_chrdev;
    }

    class_hello_cdev->ops = &class_hello_fops;
    class_hello_cdev->owner = THIS_MODULE;
    error = cdev_add(class_hello_cdev, dev, 1);
    if (error)
    {
        printk(KERN_ERR "class_hello: cdev_add failed! ");
        goto out_cdev;
    }
    
    print_dev_t(buf, dev);
    printk(KERN_WARNING "cdev add %s\n", buf);
    
    class_hello_class = class_create(THIS_MODULE, CLASSNAME); 
    if (IS_ERR(class_hello_class)) 
    { 
        error = PTR_ERR(class_hello_class); 
        goto out_chrdev; 
    } 
    device_create(class_hello_class, NULL, dev, NULL, "%s_%d-%d", DEVNAME, major, minor); 
    //memset (hello_buf, 0, sizeof(hello_buf));
    //memcpy(hello_buf, DEFAULT_MSG, sizeof(DEFAULT_MSG));
    printk(KERN_WARNING "class_hello: Hello Feng! create class done!\n");
    return 0;
 
out_cdev:
    cdev_del(class_hello_cdev);
out_chrdev:
    unregister_chrdev_region(class_hello_cdev->dev, 2);
out:
    return error;
}

static void __exit class_hello_exit(void)
{
    device_destroy(class_hello_class, dev); 
    class_destroy(class_hello_class); 
    unregister_chrdev_region(class_hello_cdev->dev, nr_devs);
    cdev_del(class_hello_cdev);
    printk(KERN_WARNING "class_hello: Goodbye Feng\n");
}

module_init(class_hello_init);
module_exit(class_hello_exit);
